package com.niiwoo.civet.trade.service.local.newRefund.refundDeal.core;

import com.alibaba.fastjson.JSON;
import com.niiwoo.civet.account.dto.response.AccountCompanyDTO;
import com.niiwoo.civet.account.service.AccountCompanyDubboService;
import com.niiwoo.civet.base.enums.FeeTypeEnum;
import com.niiwoo.civet.base.enums.RefundTypeEnum;
import com.niiwoo.civet.trade.constant.AccountConfigConstants;
import com.niiwoo.civet.trade.constant.AmountHandleConstant;
import com.niiwoo.civet.trade.dao.entity.*;
import com.niiwoo.civet.trade.dao.mapper.*;
import com.niiwoo.civet.trade.dto.newRefund.ReceiveFeeDTO;
import com.niiwoo.civet.trade.dto.newRefund.RefundFeeDTO;
import com.niiwoo.civet.trade.dto.newRefund.RefundOrderDetailDTO;
import com.niiwoo.civet.trade.enums.RefundTradeTypeEnum;
import com.niiwoo.civet.trade.service.local.newRefund.common.RefundCommonService;
import com.niiwoo.civet.trade.utils.RepaymentUtil;
import com.niiwoo.tripod.lanmao.component.LanMaoSequence;
import com.niiwoo.tripod.lanmao.enums.BusinessTypeEnum;
import com.niiwoo.tripod.lanmao.enums.TransactionTypeEnum;
import com.niiwoo.tripod.provider.exception.BizException;
import com.niiwoo.tripod.service.component.SnowflakeIdWorker;
import lombok.AllArgsConstructor;
import lombok.Data;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.math.MathContext;
import java.util.*;

/**
 * 金额分配
 */
@Service
public class RefundAllotFeeForRepaymentService {

    @Autowired
    private SnowflakeIdWorker snowflakeIdWorker;

    @Autowired
    private LanMaoSequence lanMaoSequence;

    @Autowired
    private ProjectInvestorPlanMapperExt projectInvestorPlanMapperExt;

    @Autowired
    private ProjectGuaranteePlanMapperExt projectGuaranteePlanMapperExt;

    @Autowired
    private RefundOrderDetailMapperExt refundOrderDetailMapperExt;

    @Autowired
    private RefundOrderDetailBizMapperExt refundOrderDetailBizMapperExt;

    @Autowired
    private FeeCalcForReceiveService feeCalcForReceiveService;

    @Autowired
    private ProjectBorrowerSummaryMapperExt projectBorrowerSummaryMapperExt;

    @Autowired
    private FeeCalcForRefundService feeCalcForRefundService;

    @Autowired
    private AccountConfigMapper accountConfigMapper;

    @Autowired
    private ProjectMapperExt projectMapperExt;

    @Autowired
    private AdvanceConfigMapperExt advanceConfigMapperExt;

    @Autowired
    private RefundCommonService refundCommonService;

    @Autowired
    private ProjectGuaranteeServicePlanMapperExt projectGuaranteeServicePlanMapperExt;

    private Logger logger = LoggerFactory.getLogger(RefundAllotFeeForRepaymentService.class);

    @com.alibaba.dubbo.config.annotation.Reference(version = "1.0.0")
    private AccountCompanyDubboService accountCompanyDubboService;

    /**
     * 借款用户还款分账
     * @param refundOrder
     * @return
     */
    @Transactional(propagation = Propagation.MANDATORY)
    public List<RefundOrderDetailDTO> allotFee(RefundOrder refundOrder) {
        Long projectId = refundOrder.getProjectId();
        Date currentDate = refundOrder.getCurrentDate();
        List<Integer> periods = this.spiltPeriods(refundOrder.getPeriods());
        List<RefundOrderDetailDTO> allRefundOrderDetailDTOS = new ArrayList<>();
        ProjectBorrowerSummary summary = projectBorrowerSummaryMapperExt.selectByPrimaryKey(projectId);
        Project project = projectMapperExt.selectByPrimaryKey(projectId);

        List<ProjectBorrowerPlanNew> needRefundProjectBorrowPlanNew = feeCalcForRefundService.getNeedRefundProjectBorrowPlanNew(refundOrder.getOptType(), refundOrder.getCompareDate() , summary , periods);
        if(refundOrder.getCapital().add(refundOrder.getInterest()).add(refundOrder.getPenaltyFee()).compareTo(BigDecimal.ZERO) >0){
            List<Integer> periodList = new ArrayList<>();
            for (ProjectBorrowerPlanNew projectBorrowerPlanNew : needRefundProjectBorrowPlanNew) {
                periodList.add(projectBorrowerPlanNew.getPeriod());
            }
            List<ReceiveFeeDTO> receiveFeeDTOList = feeCalcForReceiveService.getReceiveFeeDTOList(project, summary, periodList, currentDate, RefundTypeEnum.enumOf(refundOrder.getRefundType()), project.getDeadlineUnit());
            List<RefundOrderDetailDTO> refundOrderDetailDTOS = this.dealCapitalInterestPenalty(project, receiveFeeDTOList, refundOrder);
            allRefundOrderDetailDTOS.addAll(refundOrderDetailDTOS);
        }
        if(refundOrder.getManageFee().add(refundOrder.getGuaranteeFee()).add(refundOrder.getConsultingFee()).compareTo(BigDecimal.ZERO) > 0){
            if(refundOrder.getManageFee().compareTo(BigDecimal.ZERO) > 0){
                List<RefundFeeDTO> feeList = feeCalcForRefundService.getRefundFeeDTOList(needRefundProjectBorrowPlanNew, FeeTypeEnum.MANAGEMENT_FEE, refundOrder.getManageFee());
                List<RefundOrderDetailDTO> refundOrderDetailDTOS = this.dealServiceFee(refundOrder, feeList, FeeTypeEnum.MANAGEMENT_FEE, project);
                allRefundOrderDetailDTOS.addAll(refundOrderDetailDTOS);
            }
            if(refundOrder.getGuaranteeFee().compareTo(BigDecimal.ZERO) > 0){
                List<RefundFeeDTO> feeList = feeCalcForRefundService.getRefundFeeDTOList(needRefundProjectBorrowPlanNew, FeeTypeEnum.GUARANTEE_FEE, refundOrder.getGuaranteeFee());
                List<RefundOrderDetailDTO> refundOrderDetailDTOS = this.dealServiceFee(refundOrder, feeList, FeeTypeEnum.GUARANTEE_FEE, project);
                allRefundOrderDetailDTOS.addAll(refundOrderDetailDTOS);
            }
            if(refundOrder.getConsultingFee().compareTo(BigDecimal.ZERO) > 0){
                List<RefundFeeDTO> feeList = feeCalcForRefundService.getRefundFeeDTOList(needRefundProjectBorrowPlanNew, FeeTypeEnum.CONSULTING_FEE, refundOrder.getConsultingFee());
                List<RefundOrderDetailDTO> refundOrderDetailDTOS = this.dealServiceFee(refundOrder, feeList, FeeTypeEnum.CONSULTING_FEE, project);
                allRefundOrderDetailDTOS.addAll(refundOrderDetailDTOS);
            }
        }
        return allRefundOrderDetailDTOS;
    }

    /**
     * @param refundOrder
     * @param feeList
     * @param feeTypeEnum
     * @return
     */
    private List<RefundOrderDetailDTO> dealServiceFee(RefundOrder refundOrder, List<RefundFeeDTO> feeList, FeeTypeEnum feeTypeEnum,Project project){
        Long projectId = refundOrder.getProjectId();
        String batchNo = refundOrder.getBatchNo();
        List<RefundOrderDetailDTO> resultList = new ArrayList<>();
        RefundRelation refundRelation;
        AccountConfig accountConfig;
        AccountCompanyDTO accountCompanyDTO = null;
        if(FeeTypeEnum.GUARANTEE_FEE.equals(feeTypeEnum)){
            refundRelation = this.getFenRunRefundRelation(projectId, refundOrder.getTradeType());
            accountCompanyDTO = accountCompanyDubboService.getGuaranteeOrgByOrgId(project.getGuaranteeCompanyOrgId());
            accountConfig = new AccountConfig();
            accountConfig.setUserId(accountCompanyDTO.getUserId());
            accountConfig.setAccountId(accountCompanyDTO.getAccountId());
            accountConfig.setPlatformUserNo(accountCompanyDTO.getAccountNo());
        }else if(FeeTypeEnum.MANAGEMENT_FEE.equals(feeTypeEnum)){
            refundRelation = this.getFenYongRefundRelation(projectId, refundOrder.getTradeType());
            accountConfig = accountConfigMapper.selectByPrimaryKey(AccountConfigConstants.getPlatform());
        } else if(FeeTypeEnum.CONSULTING_FEE.equals(feeTypeEnum)){
            refundRelation = this.getFenRunRefundRelation(projectId, refundOrder.getTradeType());
            AccountCompanyDTO consulting = refundCommonService.getConsultingByProjectId(projectId);
            accountConfig = new AccountConfig();
            accountConfig.setUserId(consulting.getUserId());
            accountConfig.setAccountId(consulting.getAccountId());
            accountConfig.setPlatformUserNo(consulting.getAccountNo());
        }else{
            throw new BizException("资金费用类型无法找到和存管的对应关系");
        }
        if(null == accountConfig){
            throw  new BizException("平台管理费或担保服务费无法找到接收用户");
        }

        List<ProjectGuaranteeServicePlan> projectGuaranteeServicePlanList = projectGuaranteeServicePlanMapperExt.listNotReceiveByProjectIdAndFeeType(projectId, feeTypeEnum.getValue());

        logger.info("dealServiceFee refundFeeDTO:{}", JSON.toJSON(feeList));
        for (RefundFeeDTO refundFeeDTO : feeList) {
            if(BigDecimal.ZERO.compareTo(refundFeeDTO.getRefundingMoney()) == 0){
                continue;
            }

            if(refundCommonService.isCalculateInterestByDay(project.getOrgId(), project.getDeadlineUnit(), refundFeeDTO.getRefundDate(), refundOrder.getCurrentDate())){
                if(FeeTypeEnum.MANAGEMENT_FEE.equals(feeTypeEnum)){
                    refundFeeDTO.setRefundingMoney(calculateManageFeeByDay(project, refundOrder.getCurrentDate()));
                }

                if(FeeTypeEnum.GUARANTEE_FEE.equals(feeTypeEnum)){
                    refundFeeDTO.setRefundingMoney(calculateGuaranteeFeeByDay(project, refundOrder.getCurrentDate()));
                }

                if(FeeTypeEnum.CONSULTING_FEE.equals(feeTypeEnum)){
                    refundFeeDTO.setRefundingMoney(calculateConsultingFeeByDay(project, refundOrder.getCurrentDate()));
                }
            }

            // 如垫付的费用不为空，还款人在还该费用时应该还给垫付出款方
            if(!projectGuaranteeServicePlanList.isEmpty()){
                logger.info("dealServiceFee projectGuaranteeServicePlanList:{}", JSON.toJSON(projectGuaranteeServicePlanList));
                for (ProjectGuaranteeServicePlan projectGuaranteeServicePlan : projectGuaranteeServicePlanList) {
                    if(projectGuaranteeServicePlan.getCurrentPeriod().equals(refundFeeDTO.getPeriod())){
                        accountConfig.setUserId(projectGuaranteeServicePlan.getSourceUserId());
                        accountConfig.setAccountId(projectGuaranteeServicePlan.getSourceAccountId());
                        accountConfig.setPlatformUserNo(projectGuaranteeServicePlan.getSourcePlatformUserNo());
                        break;
                    } else {
                        logger.info("dealServiceFee !projectGuaranteeServicePlan.getCurrentPeriod().equals(refundFeeDTO.getPeriod())");
                        if(FeeTypeEnum.GUARANTEE_FEE.equals(feeTypeEnum)){
                            refundRelation = this.getFenRunRefundRelation(projectId, refundOrder.getTradeType());
                            assert accountCompanyDTO != null;
                            accountConfig.setUserId(accountCompanyDTO.getUserId());
                            accountConfig.setAccountId(accountCompanyDTO.getAccountId());
                            accountConfig.setPlatformUserNo(accountCompanyDTO.getAccountNo());
                        }else if(FeeTypeEnum.MANAGEMENT_FEE.equals(feeTypeEnum)){
                            refundRelation = this.getFenYongRefundRelation(projectId, refundOrder.getTradeType());
                            accountConfig = accountConfigMapper.selectByPrimaryKey(AccountConfigConstants.getPlatform());
                        } else if(FeeTypeEnum.CONSULTING_FEE.equals(feeTypeEnum)){
                            refundRelation = this.getFenRunRefundRelation(projectId, refundOrder.getTradeType());
                            AccountCompanyDTO consulting = refundCommonService.getConsultingByProjectId(projectId);
                            accountConfig.setUserId(consulting.getUserId());
                            accountConfig.setAccountId(consulting.getAccountId());
                            accountConfig.setPlatformUserNo(consulting.getAccountNo());
                        }else{
                            throw new BizException("资金费用类型无法找到和存管的对应关系");
                        }
                    }
                }
                logger.info("dealServiceFee accountConfig:{}", JSON.toJSON(accountConfig));
            }

            RefundOrderDetailDTO refundOrderDetailDTO = new RefundOrderDetailDTO();
            refundOrderDetailDTO.setId(snowflakeIdWorker.nextId());
            refundOrderDetailDTO.setRefundOrderId(refundOrder.getId());
            refundOrderDetailDTO.setBatchNo(batchNo);
            refundOrderDetailDTO.setProjectId(projectId);
            refundOrderDetailDTO.setBorrowUserId(refundOrder.getBorrowUserId());
            refundOrderDetailDTO.setDetailRequestNo(lanMaoSequence.getRequestNo());
            if(RefundTradeTypeEnum.REPAYMENT.getTradeType().equals(refundOrder.getTradeType())){
                refundOrderDetailDTO.setTradeType(TransactionTypeEnum.REPAYMENT.name());
            } else{
                refundOrderDetailDTO.setTradeType(TransactionTypeEnum.COMPENSATORY.name());
            }
            refundOrderDetailDTO.setCreateTime(new Date());
            refundOrderDetailDTO.setUpdateTime(new Date());
            refundOrderDetailMapperExt.insertSelective(refundOrderDetailDTO);

            RefundOrderDetailBiz relation = new RefundOrderDetailBiz();
            relation.setId(snowflakeIdWorker.nextId());
            relation.setRefundOrderId(refundOrder.getId());
            relation.setBatchNo(batchNo);
            relation.setProjectId(projectId);
            relation.setBorrowUserId(refundOrder.getBorrowUserId());
            relation.setCurrentPeriod(-1);
            relation.setDetailRequestNo(refundOrderDetailDTO.getDetailRequestNo());
            relation.setBizType(refundRelation.getBusinessTypeEnum().name());
            relation.setBackPlanId(-1L);
            relation.setFreezeRequestNo(refundOrder.getFreezeRequestNo());
            relation.setSourceUserId(refundOrder.getSourceUserId());
            relation.setSourceAccountId(refundOrder.getSourceAccountId());
            relation.setSourcePlatformUserNo(refundOrder.getSourcePlatformUserNo());
            relation.setTargetUserId(refundRelation.getUserId());
            relation.setTargetPlatformUserNo(refundRelation.getPlatformUserNo());
            relation.setTargetAccountId(refundRelation.getAccountId());
            relation.setAmount(BigDecimal.ZERO);
            relation.setCreateTime(new Date());
            relation.setUpdateTime(new Date());
            relation.setTradeType(refundOrder.getTradeType());
            refundOrderDetailBizMapperExt.insertSelective(relation);

            // 担保公司或平台
            RefundOrderDetailBiz biz = new RefundOrderDetailBiz();
            biz.setId(snowflakeIdWorker.nextId());
            biz.setRefundOrderId(refundOrder.getId());
            biz.setBatchNo(batchNo);
            biz.setProjectId(projectId);
            biz.setBorrowUserId(refundOrder.getBorrowUserId());
            biz.setCurrentPeriod(refundFeeDTO.getPeriod());
            biz.setDetailRequestNo(refundOrderDetailDTO.getDetailRequestNo());
            if(FeeTypeEnum.GUARANTEE_FEE.equals(feeTypeEnum)){
                biz.setBizType(BusinessTypeEnum.PROFIT.name());
                biz.setGuaranteeFee(refundFeeDTO.getRefundingMoney());
            } else if(FeeTypeEnum.MANAGEMENT_FEE.equals(feeTypeEnum)){
                AccountConfig platformAccount = accountConfigMapper.selectByPrimaryKey(AccountConfigConstants.getPlatform());
                if (accountConfig.getAccountId().equals(platformAccount.getAccountId())) {
                    biz.setBizType(BusinessTypeEnum.COMMISSION.name());
                } else {
                    logger.info("refund management_fee refundOrder:{},targetAccountConfig:{}",JSON.toJSON(refundOrder),JSON.toJSON(accountConfig));
                    biz.setBizType(BusinessTypeEnum.PROFIT.name());
                }
                biz.setManageFee(refundFeeDTO.getRefundingMoney());
            } else if(FeeTypeEnum.CONSULTING_FEE.equals(feeTypeEnum)){
                biz.setBizType(BusinessTypeEnum.PROFIT.name());
                biz.setConsultingFee(refundFeeDTO.getRefundingMoney());
            } else{
                throw new BizException("资金费用类型无法找到和存管的对应关系");
            }
            biz.setBackPlanId(-1L);
            biz.setFreezeRequestNo(refundOrder.getFreezeRequestNo());
            biz.setSourceUserId(refundOrder.getSourceUserId());
            biz.setSourceAccountId(refundOrder.getSourceAccountId());
            biz.setSourcePlatformUserNo(refundOrder.getSourcePlatformUserNo());
            biz.setTargetUserId(accountConfig.getUserId());
            biz.setTargetPlatformUserNo(accountConfig.getPlatformUserNo());
            biz.setTargetAccountId(accountConfig.getAccountId());
            biz.setAmount(refundFeeDTO.getRefundingMoney());
            biz.setCreateTime(new Date());
            biz.setUpdateTime(new Date());
            biz.setTradeType(refundOrder.getTradeType());
            refundOrderDetailBizMapperExt.insertSelective(biz);

            final List<RefundOrderDetailBiz> refundOrderDetailBizs = new ArrayList<>();
            // 分佣分润时此顺序十分关键
            refundOrderDetailBizs.add(relation);
            refundOrderDetailBizs.add(biz);
            refundOrderDetailDTO.setRefundOrderDetailBizList(refundOrderDetailBizs);
            resultList.add(refundOrderDetailDTO);
        }
        return resultList;
    }

    /**
     * 找到关联分润时需关联的存管用户号（为收取担保服务费）
     * @param projectId
     * @param tradeType
     * @return
     */
    private RefundRelation getFenRunRefundRelation(Long projectId, Byte tradeType){
        ProjectInvestorPlan relationFirst = projectInvestorPlanMapperExt.getRelationFirst(projectId);
        if(null != relationFirst){
            if(RefundTradeTypeEnum.REPAYMENT.getTradeType().equals(tradeType)){
                return new RefundRelation(relationFirst.getPlatformUserNo(), relationFirst.getUserId(), relationFirst.getAccountId(), BusinessTypeEnum.REPAYMENT);
            } else{
                return new RefundRelation(relationFirst.getPlatformUserNo(), relationFirst.getUserId(), relationFirst.getAccountId(), BusinessTypeEnum.COMPENSATORY);
            }
        }else{
            ProjectInvestorPlan relationSecond = projectInvestorPlanMapperExt.getRelationSecond(projectId);
            if(null != relationSecond){
                if(RefundTradeTypeEnum.REPAYMENT.getTradeType().equals(tradeType)){
                    return new RefundRelation(relationSecond.getPlatformUserNo(), relationSecond.getUserId(), relationSecond.getAccountId(), BusinessTypeEnum.REPAYMENT);
                } else{
                    return new RefundRelation(relationSecond.getPlatformUserNo(), relationSecond.getUserId(), relationSecond.getAccountId(), BusinessTypeEnum.COMPENSATORY);
                }
            }else{
                throw new BizException("分润时无法到关联的用户");
            }
        }
    }

    /**
     * 找到分佣时需关联的存管用户号（为收取平台管理费）
     * @param projectId
     * @return
     */
    private RefundRelation getFenYongRefundRelation(Long projectId, Byte tradeType){
        ProjectInvestorPlan relationFirst = projectInvestorPlanMapperExt.getRelationFirst(projectId);
        if(null != relationFirst){
            if(RefundTradeTypeEnum.REPAYMENT.getTradeType().equals(tradeType)){
                return new RefundRelation(relationFirst.getPlatformUserNo(), relationFirst.getUserId(), relationFirst.getAccountId(), BusinessTypeEnum.REPAYMENT);
            } else{
                return new RefundRelation(relationFirst.getPlatformUserNo(), relationFirst.getUserId(), relationFirst.getAccountId(), BusinessTypeEnum.COMPENSATORY);
            }
        }else{
            ProjectGuaranteePlan projectGuaranteePlan = projectGuaranteePlanMapperExt.getRelation(projectId);
            if(null != projectGuaranteePlan){
                return new RefundRelation(projectGuaranteePlan.getPlatformUserNo(), projectGuaranteePlan.getUserId(), projectGuaranteePlan.getAccountId(), BusinessTypeEnum.COMPENSATORY_REPAYMENT);
            }else{
                throw new BizException("分润时无法到关联的用户");
            }
        }
    }

    /**
     * 还款关系
     */
    @Data
    @AllArgsConstructor
    private static class RefundRelation{
        private String platformUserNo;
        private String userId;
        private Long accountId;
        private BusinessTypeEnum businessTypeEnum;
    }





    /**
     * 本利罚分账
     * @param receiveFeeDTOList
     * @param refundOrder
     * @return
     */
    private List<RefundOrderDetailDTO> dealCapitalInterestPenalty(Project project, List<ReceiveFeeDTO> receiveFeeDTOList, RefundOrder refundOrder){
        // 先处理利息
        Date currentDate = refundOrder.getCurrentDate();
        String batchNo = refundOrder.getBatchNo();
        Long projectId = refundOrder.getProjectId();
        // 分账
        List<RefundOrderDetailDTO> resultList = new ArrayList<>();
        BigDecimal capital = refundOrder.getCapital();
        BigDecimal interest = refundOrder.getInterest();
        BigDecimal penaltyFee = refundOrder.getPenaltyFee();
        Map<Long,BigDecimal> expectInterestMap = new HashMap<>();//key investOrderId,value=预期利息，记录提前结清无法统计预期利息
        logger.debug("dealCapitalInterestPenalty.receiveFeeDTOList={}", JSON.toJSONString(receiveFeeDTOList));
        for (ReceiveFeeDTO receiveFeeDTO : receiveFeeDTOList) {
            if(capital.compareTo(BigDecimal.ZERO) == 0
                    && interest.compareTo(BigDecimal.ZERO) == 0
                    && penaltyFee.compareTo(BigDecimal.ZERO) == 0){
                break;
            }
            ReceiveFeeDTO r = new ReceiveFeeDTO();
            if(capital.compareTo(receiveFeeDTO.getCapital()) >= 0){
                r.setCapital(receiveFeeDTO.getCapital());
                capital = capital.subtract(receiveFeeDTO.getCapital());
            } else{
                r.setCapital(capital);
                capital = BigDecimal.ZERO;
            }
            if(interest.compareTo(receiveFeeDTO.getInterest()) >= 0){
                r.setInterest(receiveFeeDTO.getInterest());
                interest = interest.subtract(receiveFeeDTO.getInterest());
            } else{
                r.setInterest(interest);
                interest = BigDecimal.ZERO;
            }
            if(penaltyFee.compareTo(receiveFeeDTO.getPenaltyFee()) >= 0){
                r.setPenaltyFee(receiveFeeDTO.getPenaltyFee());
                penaltyFee = penaltyFee.subtract(receiveFeeDTO.getPenaltyFee());
            } else{
                r.setPenaltyFee(penaltyFee);
                penaltyFee = BigDecimal.ZERO;
            }

            BigDecimal expectInterest = BigDecimal.ZERO;
            // 提前结清免息
            if (BigDecimal.ZERO.compareTo(receiveFeeDTO.getInterest()) == 0
                    && r.getCapital().compareTo(receiveFeeDTO.getCapital()) == 0
                    && r.getInterest().compareTo(receiveFeeDTO.getInterest()) == 0
                    && r.getPenaltyFee().compareTo(receiveFeeDTO.getPenaltyFee()) == 0){
                expectInterest = receiveFeeDTO.getExpectInterest();
            }

            // 如果是按日计息还款，赋值投资人 应该减少的预收利息
            if(refundCommonService.isCalculateInterestByDay(project.getOrgId(), project.getDeadlineUnit(), receiveFeeDTO.getReceiveDate(), currentDate)){
                expectInterest = receiveFeeDTO.getExpectInterest();
            }

            if(r.getCapital().add(r.getInterest()).add(r.getPenaltyFee()).compareTo(BigDecimal.ZERO) > 0){
                RefundOrderDetailDTO refundOrderDetailDTO = new RefundOrderDetailDTO();
                refundOrderDetailDTO.setId(snowflakeIdWorker.nextId());
                refundOrderDetailDTO.setRefundOrderId(refundOrder.getId());
                refundOrderDetailDTO.setBatchNo(batchNo);
                refundOrderDetailDTO.setProjectId(projectId);
                refundOrderDetailDTO.setBorrowUserId(refundOrder.getBorrowUserId());
                refundOrderDetailDTO.setDetailRequestNo(lanMaoSequence.getRequestNo());
                if(RefundTradeTypeEnum.REPAYMENT.getTradeType().equals(refundOrder.getTradeType())){
                    refundOrderDetailDTO.setTradeType(TransactionTypeEnum.REPAYMENT.name());
                } else{
                    refundOrderDetailDTO.setTradeType(TransactionTypeEnum.COMPENSATORY.name());
                }
                refundOrderDetailDTO.setCreateTime(new Date());
                refundOrderDetailDTO.setUpdateTime(new Date());
                refundOrderDetailMapperExt.insertSelective(refundOrderDetailDTO);

                RefundOrderDetailBiz biz = new RefundOrderDetailBiz();
                biz.setId(snowflakeIdWorker.nextId());
                biz.setRefundOrderId(refundOrder.getId());
                biz.setBatchNo(batchNo);
                biz.setProjectId(projectId);
                biz.setBorrowUserId(refundOrder.getBorrowUserId());
                biz.setCurrentPeriod(receiveFeeDTO.getPeriod());
                biz.setDetailRequestNo(refundOrderDetailDTO.getDetailRequestNo());
                if(RefundTradeTypeEnum.REPAYMENT.getTradeType().equals(refundOrder.getTradeType())){
                    biz.setBizType(receiveFeeDTO.getBusinessTypeEnum().name());
                } else{
                    biz.setBizType(BusinessTypeEnum.COMPENSATORY.name());
                }
                biz.setBackPlanId(receiveFeeDTO.getPlanId());
                biz.setFreezeRequestNo(refundOrder.getFreezeRequestNo());
                biz.setSourceUserId(refundOrder.getSourceUserId());
                biz.setSourceAccountId(refundOrder.getSourceAccountId());
                biz.setSourcePlatformUserNo(refundOrder.getSourcePlatformUserNo());
                biz.setTargetAccountId(receiveFeeDTO.getAccountId());
                biz.setTargetUserId(receiveFeeDTO.getUserId());
                biz.setTargetPlatformUserNo(receiveFeeDTO.getPlatformUserNo());
                biz.setCapital(r.getCapital());
                biz.setInterest(r.getInterest());
                biz.setPenaltyFee(r.getPenaltyFee());
                biz.setAmount(biz.getCapital().add(biz.getInterest()).add(biz.getPenaltyFee()));
                biz.setExpectInterest(expectInterest.add(expectInterestMap.getOrDefault(receiveFeeDTO.getInvestOrderId(),BigDecimal.ZERO)));
                biz.setCreateTime(new Date());
                biz.setUpdateTime(new Date());
                biz.setTradeType(refundOrder.getTradeType());
                refundOrderDetailBizMapperExt.insertSelective(biz);

                final List<RefundOrderDetailBiz> refundOrderDetailBizs = new ArrayList<>();
                refundOrderDetailBizs.add(biz);
                refundOrderDetailDTO.setRefundOrderDetailBizList(refundOrderDetailBizs);
                resultList.add(refundOrderDetailDTO);
            }else if (RefundTypeEnum.OVERDEPT.getRefundType().equals(refundOrder.getRefundType())
                    && r.getCapital().add(r.getInterest()).add(r.getPenaltyFee()).compareTo(BigDecimal.ZERO) == 0){
                BigDecimal expectInterestForOverdebt = expectInterestMap.getOrDefault(receiveFeeDTO.getInvestOrderId(),BigDecimal.ZERO);
                expectInterestMap.put(receiveFeeDTO.getInvestOrderId(),expectInterestForOverdebt.add(expectInterest));
                logger.info("先息后本提前结清，预期利息编差 expectInterestMap = {},investorOrderId={}",JSON.toJSONString(expectInterestMap),receiveFeeDTO.getInvestOrderId());
            }
        }
        return resultList;
    }

    private List<Integer> spiltPeriods(String periods){
        List<Integer> periodList = new ArrayList<Integer>();
        if(StringUtils.isNotEmpty(periods)){
            String[] periodArray = periods.split(",");
            for(String period : periodArray){
                periodList.add(Integer.parseInt(period));
            }
        }
        return periodList.size()==0?null:periodList;
    }

    private BigDecimal calculateManageFeeByDay(Project project, Date currentDate) {
        BigDecimal dayRate = project.getManageRate().divide(BigDecimal.valueOf(project.getDeadline()), MathContext.DECIMAL128);
        return calculateByDay(project.getContractAmount(), dayRate, currentDate, project.getFullSuccessTime());
    }

    private BigDecimal calculateGuaranteeFeeByDay(Project project, Date currentDate) {
        BigDecimal dayRate = project.getGuaranteeRate().divide(BigDecimal.valueOf(project.getDeadline()), MathContext.DECIMAL128);
        return calculateByDay(project.getContractAmount(), dayRate, currentDate, project.getFullSuccessTime());
    }

    private BigDecimal calculateConsultingFeeByDay(Project project, Date currentDate) {
        BigDecimal dayRate = project.getConsultingRate().divide(BigDecimal.valueOf(project.getDeadline()), MathContext.DECIMAL128);
        return calculateByDay(project.getContractAmount(), dayRate, currentDate, project.getFullSuccessTime());
    }

    private BigDecimal calculateByDay(BigDecimal amount, BigDecimal dayRate, Date currentDate, Date fullSuccessDate) {
        logger.info("calculateByDay amount:{},dayRate:{},currentDate:{},fullSuccessDate:{}", amount, dayRate, currentDate, fullSuccessDate);
        int currentDeadline = RepaymentUtil.getOverdueDay(fullSuccessDate, currentDate);
        // 满标日当天进行还款计息一天
        currentDeadline = currentDeadline == 0 ? 1 : currentDeadline;
        logger.info("calculateByDay currentDeadline:{}", currentDeadline);

        BigDecimal result = amount.multiply(dayRate).multiply(new BigDecimal(currentDeadline)).setScale(AmountHandleConstant.CALCULATE_PRECISION_TWO, BigDecimal.ROUND_HALF_EVEN);
        logger.info("calculateByDay result:{}", result);
        return result;
    }
}
